#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# @Description: 检查
import os
import random
import re
import signal
import time

import constants
from constants import SYSTEM_DU_SH, CHECK_VDBFILE, CHECK_FILE_GROUP, CHECK_FILE_AUTH, CHECK_SPACE, CHECK_REPLICAS_DISK, \
    QDFS_SHOW_RW_STATUS, QDFS_SHOW_DEVICE, QDFS_SHOW_ERROR_COUNT
from modules.operationBase import OperationBase
from modules.qdisk import get_disk_list
from utils.logger import Logger

log = Logger()


def parse_str_format_float(size_str: str) -> str:
    """
    将2T、7T这种压测出的大文件，进行format操作，因为du -sh看到的是浮点型，包含T,则修改，否则返回原字符
    :param size_str: format size
    :return:
    """
    if size_str.endswith('G'):
        # 提取数字部分
        size_num = float(re.match(r'(\d+)G', size_str).group(1))
        if size_num < 1000:
            # 如果数字部分是3位数，直接返回
            return size_str
        else:
            # 如果数字部分是4位数及以上，转换为T单位
            size_num_t = round(size_num / 1024, 1)
            return f"{size_num_t}T"
    if size_str.endswith('T'):
        return re.sub(r'(\d+)([TGMK])', r'\1.0\2', size_str)
    return size_str


class Check(OperationBase):
    def __init__(self, parse_args):
        super().__init__(parse_args)

    def qdfs_check_mount_point(self):
        res = self.ssh.exec_cmd()
        if res.strip() == "not a qdfs filesystem":
            logging.info("qdfs is not mounted")
            pass
        else:
            logging.info("qdfs is mounted, please clear it")
            os.kill(os.getpid(), signal.SIGTERM)

    def qdfs_parameter_check(self):
        """
        qdfs参数检查
        :return:
        """
        qdisk_path = get_disk_list(status="USED")
        qdisk = random.choices(qdisk_path, k=1)
        res = self.ssh.exec_cmd(constants.QDFS_CHECK_BUCKET_SIZE.format(''.join(qdisk)))
        for x in res.strip().split("\n"):
            if x != "512KiB":
                log.info("qdfs bucket error its not 512 KiB, please check")
                os.kill(os.getpid(), signal.SIGTERM)
            else:
                log.info("qdfs bucket is 512 KiB,going down")

        time.sleep(10)
        for i in qdisk_path:
            res_1  = self.ssh.exec_cmd(constants.QDFS_CHECK_BLOCK_SIZE.format(i))
            for x in res_1.strip().split("\n"):
                if x != "4.00KiB":
                    log.info("%s  block size its not 4.00KiB, please check")
                    os.kill(os.getpid(), signal.SIGTERM)
                else:
                    log.info("%s block size is 4.00KiB,going down" % i)

        time.sleep(10)
        for i in qdisk_path:
            res_2 = self.ssh.exec_cmd(constants.QDFS_CHECK_METADATA_CHECKSUM.format(i))
            if res_2.strip() != "[none]":
                log.info("%s metadata_check sum its not none, exit")
                os.kill(os.getpid(), signal.SIGTERM)
            else:
                log.info("%s metadata_check sum is none,going down" % i)

        time.sleep(10)
        for i in qdisk_path:
            res_3 = self.ssh.exec_cmd(constants.QDFS_CHECK_DATA_CHECKSUM.format(i))
            if res_3.strip() != "[none]":
                log.info("%s data_check sum its not none, exit")
                os.kill(os.getpid(), signal.SIGTERM)
            else:
                log.info("%s data_check sum is none,going down" % i)

    def check_file_size(self, size: str) -> bool:
        """
        检查文件大小
        :param size: 预期大小
        :return:
        """
        res = self.ssh.exec_cmd(SYSTEM_DU_SH.format(self.point))
        if res.strip() != parse_str_format_float(size):
            log.error(f"create {size} is failed，because file result is {r}")
            return False
        else:
            log.success(f"create {size} is success")
            return True

    def check_vdgfile(self):
        """
        检查vdbench的文件
        :return:
        """
        res = self.ssh.exec_cmd(command=CHECK_VDBFILE.format(self.point))
        files = res.strip().split('\n')
        log.info(f"files is {files}")

        for i in files:
            if i:
                log.info(f"vdb file is {i}")
            else:
                log.error("vdb file is not exists")
                os.kill(os.getpid(), signal.SIGTERM)

    def check_qdfs_chown(self):
        """
        检查qdfs所属组
        :return:
        """
        res = self.ssh.exec_cmd(command=CHECK_FILE_GROUP.format(self.point))
        if res.strip() != "":
            log.error("qdfs user permission is error, exit")
            os.kill(os.getpid(), signal.SIGTERM)

        log.info("qdfs user permission is normal,going down")

    def check_qdfs_chmod(self):
        """
        检查qdfs权限
        :return:
        """
        res = self.ssh.exec_cmd(command=CHECK_FILE_AUTH.format(self.point))
        if res.strip() != "":
            log.error("qdfs rwx permission is error, exit")
            os.kill(os.getpid(), signal.SIGTERM)

        log.info("qdfs rwx permission is normal, going down")

    def check_qdfs_space(self):
        """
        检查qdfs空间
        :return:
        """
        res = self.ssh.exec_cmd(command=CHECK_SPACE.format(self.point))
        if res.strip() != "":
            log.error("qdfs space file still exists, exit")
            os.kill(os.getpid(), signal.SIGTERM)

        log.info("qdfs file is delete, going down")

    def check_replicas_disk(self, number: int):
        """
        检查副本的磁盘数量
        :param number: 预期的磁盘数量
        :return:
        """
        res = self.ssh.exec_cmd(command=CHECK_REPLICAS_DISK.format(self.point))
        disk_list = []
        for i in res.strip().split('\n'):
            disk_list.append(i)

        for nvme_number in disk_list:
            device = nvme_number.split()
            if len(device) == int(number):
                log.info(f"qdfs replicas disk number is normal")
            else:
                log.error(f"{device} error will exit")
                os.kill(os.getpid(), signal.SIGTERM)

    def check_fs_rw(self):
        """
        检查qdfs rw status
        :return:
        """
        res = self.ssh.exec_cmd(command=QDFS_SHOW_RW_STATUS.format(self.point))
        result = "".strip(res)
        if result in "RW":
            log.info("qdfs filesystem is RW, its ok")
        else:
            log.error("err with %s" % result)
            os.kill(os.getpid(), signal.SIGTERM)

    def check_disk_rw(self):
        res = self.ssh.exec_cmd(QDFS_SHOW_DEVICE.format(self.point))
        lines = res.strip().split('\n')
        for line in lines:
            parts = line.split()
            device_info = parts[3].strip('():')
            nvme_info = parts[4]
            rw_info = parts[5]
            if rw_info == 'rw':
                log.info(f"device: {device_info}, nvme: {nvme_info}, rw_info: {rw_info} is ok, continue")
            else:
                log.error(f"device: {device_info}, nvme: {nvme_info}, rw_info: {rw_info}, please check")
                os.kill(os.getpid(), signal.SIGTERM)

    def check_qdfs_rw_error_count(self):
        res = self.ssh.exec_cmd(QDFS_SHOW_ERROR_COUNT.format(self.point))
        result = res.strip().split('\n')
        for i in range(0, len(result), 2):
            # 提取 device 和 nvme 信息
            device_line = result[i]
            device_parts = device_line.split()
            device_info = device_parts[3].strip('():')  # device 信息
            nvme_info = device_parts[4]  # nvme 信息

            # 提取 errors 信息
            errors_line = result[i + 1]
            errors_parts = errors_line.split()
            read_errors = int(errors_parts[1])  # 读错误次数
            write_errors = int(errors_parts[2])  # 写错误次数
            if read_errors > 0 or write_errors > 0:
                log.error(
                    f"device id {device_info} {nvme_info} has {read_errors} read errors and {write_errors} write errors")
                os.kill(os.getpid(), signal.SIGTERM)
            else:
                log.info(f"device id {device_info} {nvme_info} has no read or write errors")

    def check_qdfs_replicas_user(self):
        res = self.ssh.exec_cmd(f"qdfs show {self.point} -h | grep user")
        log.info("start user replicas check.....")
        result_line = [
            line.strip() for line in res.split('\n')
            if line.strip().startswith('user:') and 'nvme' in line
        ]
        for line in result_line:
            parts = line.split()
            if parts[4].startswith('nvme'):
                log.info(f"{parts[3], parts[4]} is normal, going down")
                time.sleep(2)
            else:
                log.error("have single user replicas, pleas check....")
                break

    def check_qdfs_replicas_btree(self):
        res = self.ssh.exec_cmd(f"qdfs show {self.point} -h | grep btree")
        log.info("start btree replicas check.....")
        result_line = [
            line.strip() for line in res.split('\n')
            if line.strip().startswith('btree:') and 'nvme' in line
        ]
        for line in result_line:
            parts = line.split()

            if parts[4].startswith('nvme'):
                log.info(f"{parts[3], parts[4]} is normal, going down")
                time.sleep(2)
            else:
                log.error("have single btree replicas, please check")
                break

    def check_fg_remove_test(self, mode):
        """
        拔盘测试之后的一系列检查
        :param mode: all or single
        :return:
        """
        log.info("will check filesystem RW state")
        self.check_fs_rw()
        log.info("will check disk rw state")
        self.check_disk_rw()
        log.info("will check error count")
        self.check_qdfs_rw_error_count()
        if mode == "all":
            log.info("will check filesystem RW state")
            self.check_fs_rw()
        log.info("will check replicas number")
        self.check_qdfs_replicas_btree()
        time.sleep(20)
        self.check_qdfs_replicas_user()
        log.info("will continue remove disk")

    def check_ob(self):
        """
        检查ob进程
        :return:
        """
        ob_check = self.ssh.exec_cmd("ps -elf | grep observer |grep -v grep | awk '{print $4}'")
        if ob_check.strip() is None:
            log.error("observer start failed")
            os.kill(os.getpid(), signal.SIGTERM)

    def check_sysbench(self):
        """
        检查sysbench
        :return:
        """
        sysbench_check = self.ssh.exec_cmd("ps -elf | grep oltp_read_write | grep -v grep | awk '{print $4}'")
        if sysbench_check.strip() is None:
            log.error("sysbench start failed")
            os.kill(os.getpid(), signal.SIGTERM)

    def check_replicas_failgroup(self):
        """
        检查携带fg的副本分布情况
        :return:
        """
        pass
